/**
 * <pre>
 * 799.香槟塔
 * 我们把玻璃杯摆成金字塔的形状，其中第一层有 1 个玻璃杯， 第二层有 2 个，
 * 依次类推到第 100 层，每个玻璃杯 (250ml) 将盛有香槟。
 * 从顶层的第一个玻璃杯开始倾倒一些香槟，当顶层的杯子满了，
 * 任何溢出的香槟都会立刻等流量的流向左右两侧的玻璃杯。
 * 当左右两边的杯子也满了，就会等流量的流向它们左右两边的杯子，依次类推。
 * （当最底层的玻璃杯满了，香槟会流到地板上）
 * 例如，在倾倒一杯香槟后，最顶层的玻璃杯满了。
 * 倾倒了两杯香槟后，第二层的两个玻璃杯各自盛放一半的香槟。
 * 在倒三杯香槟后，第二层的香槟满了 - 此时总共有三个满的玻璃杯。
 * 在倒第四杯后，第三层中间的玻璃杯盛放了一半的香槟，
 * 他两边的玻璃杯各自盛放了四分之一的香槟，如下图所示。
 * 现在当倾倒了非负整数杯香槟后，
 * 返回第 i 行 j 个玻璃杯所盛放的香槟占玻璃杯容积的比例（ i 和 j 都从0开始）。
 * 示例 1:
 * 输入: poured(倾倒香槟总杯数) = 1, query_glass(杯子的位置数) = 1, query_row(行数) = 1
 * 输出: 0.00000
 * 解释: 我们在顶层（下标是（0，0））倒了一杯香槟后，没有溢出，因此所有在顶层以下的玻璃杯都是空的。
 * 示例 2:
 * 输入: poured(倾倒香槟总杯数) = 2, query_glass(杯子的位置数) = 1, query_row(行数) = 1
 * 输出: 0.50000
 * 解释: 我们在顶层（下标是（0，0）倒了两杯香槟后，有一杯量的香槟将从顶层溢出，位于（1，0）的玻璃杯和（1，1）的玻璃杯平分了这一杯香槟，所以每个玻璃杯有一半的香槟。
 * 示例 3:
 * 输入: poured = 100000009, query_row = 33, query_glass = 17
 * 输出: 1.00000
 * 提示:
 * 0 <= poured <= 10<sup>9</sup>
 * 0 <= query_glass <= query_row < 100
 * </pre>
 */
public class ChampagneTower_799 extends AbsSolution
{
    public static ChampagneTower_799 getInstance() {
        return new ChampagneTower_799();
    }

    /*
0    1=15
1    1/2=14/2     1/2=14/2
2    1/4=12/4     2/4=24/4     1/4=12/4
3    8/8=0        28/8=3.5     28/8         8/8
4    1/16         4/16=1.25    6/16=2.5     4/16=1.25    1/16
5    1/32         1/32=0.125   1/32=0.875   1/32=0.875   1/32=0.125    1/32
     */

    /**
     * 快速判断
     *
     * @param poured     总杯数
     * @param queryRow   行标
     * @param queryGlass 列标
     * @return 1或0, 或-1, 若-1, 则为无法快速判断
     */
    private double fastCheck(int poured, int queryRow, int queryGlass)
    {
        /*
        每行最慢装满为首尾, 又有每行首尾只能由上一行首尾溢出
        故上一行首尾未满, 则当前行首尾必空
        题中poured的值域, 最多完整装满28行全部
        故大于29行首尾必空
         */
        if (queryRow > 29) {
            if (isFirstOrLast(queryRow, queryGlass)) return 0D;
        }
        else {
            // 求完整装满所查行所需数量
            int fullQueryRowPoured = fullCurrentRowAllGlassNeed(queryRow);
            // 杯数大于装满当前行所需数量, 当前行所有杯均满
            if (poured >= fullQueryRowPoured) {return 1D;}
            // 小于装满上一行所需数量, 当前行首尾必空
            else if (fullCurrentRowAllGlassNeed(queryRow - 1) > poured
                    && isFirstOrLast(queryRow, queryGlass)) {return 0D;}
        }
        return -1;
    }

    // 是否为一行首尾
    private boolean isFirstOrLast(int queryRow, int queryGlass)
    {
        return queryGlass == 0 || queryGlass == queryRow;
    }

    /**
     * @param poured     杯数
     * @param queryRow   i行
     * @param queryGlass j列
     */
    public double champagneTower(int poured, int queryRow, int queryGlass)
    {
        double r = fastCheck(poured, queryRow, queryGlass);
        if (r == -1) {
            // 无法快速判断, 开始循环扫描
            double[] row = new double[1];
            row[0] = poured;
            // 至多扫描至当前行
            for (int i = 1; i <= queryRow; i++) {
                int cols = Math.min(i, queryGlass) + 1;
                double[] next = new double[cols];
                boolean overflow = false; // 溢出标记, 若当前行无溢出, 则下行全空
                for (int j = 0; j < cols; j++) {
                    if (j == 0 || j == i) {
                        next[j] += overflowPart(row[0]);
                    }
                    else {
                        next[j] +=
                                overflowPart(row[j]) + overflowPart(row[j - 1]);
                    }
                    // 更新溢出标记
                    overflow = overflow || next[j] > 1D;
                }
                if (overflow || i == queryRow) { //  有溢出标记, 或为查询行
                    row = next; // 更新当前行
                }
                else {return 0D;} // 否则提前结束
            }
            return Math.min(row[queryGlass], 1D);
        }
        return r;
    }

    private double overflowPart(double v)
    {
        return Math.max(v - 1, 0D) / 2D;
    }

    /**
     * 因行标从0起始, 故相当于求当前行-1, 即当前行之前所有杯子数
     *
     * @param row 行标(从0起始)
     * @return 当前行之前所有杯子数
     */
    private int fullCurrentRowAllGlassNeed(int row)
    {
        return (1 << (row + 1)) - 1;
    }
}
